package com.hhd.flow.engine.cmd.impl;

import com.hhd.flow.engine.cmd.PassTaskContext;
import com.hhd.flow.engine.utils.CommonUtils;
import com.hhd.flow.engine.utils.FlowUtils;
import com.hhd.flow.engine.vo.*;
import com.hhd.flow.entity.*;
import lombok.experimental.SuperBuilder;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

@SuperBuilder(toBuilder = true)
public abstract class PassAbleCommand<T> extends FlowProcessEventMultiCasterCommand<T> {
    protected void passStart(FlowNode flowNode, PassTaskContext context) {
        String flowTaskId = context.getFlowTaskId();
        FlowTask flowTask = context.getFlowTask();
        //删除开始节点的任务
        getEngine().getFlowTaskService().removeById(flowTaskId);
        //创建开始节点的历史记录
        getEngine().getFlowTaskHistoryService().save(CommonUtils.copyTo(flowTask, FlowTaskHistory.class));
        //发布开始节点的结束事件
        publishStartProcessAfterEvent(context, (StartProcessCommand) this);
        //添加路径
        savePath(context.addPath(flowNode.getId()));
    }

    protected void passEndTask(FlowNode flowNode, FlowTask flowTask, PassTaskContext context) {
        FlowTaskHistory flowTaskHistory = CommonUtils.copyTo(flowTask, FlowTaskHistory.class);
        getEngine().getFlowTaskService().removeById(flowTask.getId());
        getEngine().getFlowTaskHistoryService().save(flowTaskHistory);

        context.getFlowProcessInstance().setApprovedType(ProcessApproveType.approve.name());
        context.getFlowProcessInstance().setApprovedTypeName(ProcessApproveType.approve.getTitle());

        endProcess(context.getFlowProcessInstance(), ProcessApproveType.approve, true);
        publishProcessAfterApprovedEvent(context);
    }

    protected void passUserTask(FlowNode flowNode, FlowTask flowTask, PassTaskContext context) {
        //把还没有审的用户任务直接删除，说明这些用户任务已经不需要审批了
        getEngine().getFlowUserTaskService().lambdaUpdate()
                .eq(FlowUserTask::getProcessInstanceId, flowTask.getProcessInstanceId())
                .eq(FlowUserTask::getTaskDefinitionId, flowTask.getTaskDefinitionId())
                .eq(FlowUserTask::getNotify, false)
                .remove();

        //发布任务结束前事件
        publishUserTaskCompleteBeforeEvent(flowNode, flowTask, context);
        //设置节点审批结束时间
        flowTask.setCompleteTime(new Date());
        //删除用户任务
        getEngine().getFlowTaskService().removeById(flowTask.getId());
        //创建用户任务历史记录
        getEngine().getFlowTaskHistoryService().save(CommonUtils.copyTo(flowTask, FlowTaskHistory.class));
        //发布任务结束后事件
        publishUserTaskCompleteAfterEvent(flowNode, flowTask, context);
        //添加节点路径
        savePath(context.addPath(flowNode.getId()));

        //经过这个节点以后不允许撤回
        UserTask userTask = context.getFlowModel().getUserTaskById(flowNode.getId());
        if (Boolean.TRUE.equals(userTask.isPassNodeCannotWithdraw())) {
            context.getFlowProcessInstance().setCannotWidthdraw(true);
            context.getFlowProcessInstance().setCannotWithdrawMessage(userTask.getPassNodeCannotWithdrawMessage());

            getEngine().getFlowProcessInstanceService().lambdaUpdate()
                    .eq(FlowProcessInstance::getId, flowTask.getProcessInstanceId())
                    .set(FlowProcessInstance::getCannotWidthdraw, true)
                    .set(FlowProcessInstance::getCannotWithdrawMessage, userTask.getPassNodeCannotWithdrawMessage())
                    .update();
        }
    }

    protected void savePath(FlowPath flowPath) {
        getEngine().getFlowPathService().saveOrUpdate(flowPath);
    }

    protected List<FlowTask> enterUserTask(FlowNode flowNode, PassTaskContext context) {
        //保存节点的路径
        savePath(context.addPath(flowNode.getId()));

        //获取用户任务的节点定义
        UserTask userTask = context.getFlowModel().getUserTaskById(flowNode.getId());

        //根据任务定义，找到审批人
        List<FlowUser> flowUsers = loadFlowUsers(context, userTask);

        //发布审批之前的事件
        publishBeforeEnterUserTask(userTask, context, flowUsers);

        //创建一个流程任务
        FlowTask flowTask = createFlowTaskForUserTask(context, userTask, flowUsers);

        //根据任务的定义和人员，创建多个用户审批任务
        List<FlowUserTask> flowUserTasks = createFlowUserTasks(flowTask, flowUsers, context, userTask);

        //发布用户任务进入后的事件
        publishAfterEnterUserTask(userTask, context, flowUsers, flowTask, flowUserTasks);

        return CommonUtils.asList(flowTask);
    }

    private FlowTask createFlowTaskForUserTask(PassTaskContext context, UserTask userTask, List<FlowUser> flowUsers) {
        FlowTask flowTask = FlowUtils.createFlowTask(userTask, flowUsers, context);
        getEngine().getFlowTaskService().save(flowTask);
        return flowTask;
    }

    private List<FlowUser> loadFlowUsers(PassTaskContext context, UserTask userTask) {
        if (userTask.isAddCountSign()) {
            return FlowUtils.getAddCountSignUsers(userTask);
        }
        UserManualSelect userManualSelect = context.getUserManualSelect();
        if (!CommonUtils.isEmpty(userManualSelect) && !CommonUtils.isEmpty(userManualSelect.getSelect())) {
            for (UserNodeSelect userNodeSelect : userManualSelect.getSelect()) {
                if (userTask.getId().equals(userNodeSelect.getNodeId())) {
                    userTask.setAutoComplete(false);
                    return userNodeSelect.getUsers();
                }
            }
        }
        List<FlowUser> flowUsers = getEngine().loadFlowUser(context.getFormTypeId(), context.getFormId(), userTask, context);
        CommonUtils.isEmptyThrow(flowUsers, new RuntimeException("没有找到下一个节点的审批人！"));
        return flowUsers;
    }

    protected List<FlowTask> enterEnd(FlowNode flowNode, PassTaskContext context) {
        FlowTask flowTask = new FlowTask();
        flowTask.setTaskName("结束");
        flowTask.setTaskDefinitionId("end");
        flowTask.setType(flowNode.getType().name());
        flowTask.setProcessDefinitionId(context.getFlowProcessInstance().getProcessDefinitionId());
        flowTask.setProcessInstanceId(context.getFlowProcessInstanceId());
        getEngine().getFlowTaskService().save(flowTask);
        savePath(context.addPath(flowNode.getId()));
        publishProcessBeforeApprovedEvent(context);
        return CommonUtils.asList(flowTask);
    }

    private void endProcess(FlowProcessInstance flowProcessInstance, ProcessApproveType approveType, Boolean approved) {
        FlowProcessInstanceHistory flowProcessInstanceHistory = FlowUtils.createFlowProcessInstanceHistory(flowProcessInstance, approveType, approved);
        getEngine().getFlowProcessInstanceHistoryService().save(flowProcessInstanceHistory);
        getEngine().getFlowProcessInstanceService().removeById(flowProcessInstance.getId());
    }

    private List<FlowUserTask> createFlowUserTasks(FlowTask flowTask, List<FlowUser> flowUsers, PassTaskContext context, UserTask userTask) {
        UserTask.ExecuteWay executeWay = UserTask.ExecuteWay.forName(flowTask.getExecuteWay());
        List<FlowUserTask> flowUserTasks = CommonUtils.newList();
        if (executeWay == UserTask.ExecuteWay.single
                || executeWay == UserTask.ExecuteWay.multi
                || userTask.isNotify() //如果是知会, 那就直接把所有的用户任务都创建出来
                || executeWay == UserTask.ExecuteWay.multiCompetition) {
            //如果单用户找到了多个人，那就直接当做多用户审批
            flowUserTasks = FlowUtils.createFlowUserTasks(flowTask, flowUsers, context.getFlowProcessInstance(), userTask);
        } else if (executeWay == UserTask.ExecuteWay.multiSequence) {
            flowUserTasks = FlowUtils.createFlowUserTasks(flowTask, CommonUtils.asList(flowUsers.get(0)), context.getFlowProcessInstance(), userTask);
        }
//        万一当前节点配置了手动选择，但是没有被手动选择（可能是手动选择的程序出了问题），那就还继续流转吧
//        if (userTask.isManualSelectUser() && flowUserTasks.size() > 1) {//如果当前节点需要手动选择，那么就不再向下流转
//            for (FlowUserTask flowUserTask : flowUserTasks) {
//                flowUserTask.setSupportAutoComplete(false);
//            }
//        }
        for (FlowUserTask flowUserTask : flowUserTasks) {
            getEngine().getFlowUserTaskService().save(flowUserTask);
        }
        return flowUserTasks;
    }

    protected void passStartGateway(Gateway gateway, FlowTask flowTask, PassTaskContext context) {
        getEngine().getFlowTaskService().removeById(flowTask.getId());
        FlowTaskHistory flowTaskHistory = CommonUtils.copyTo(flowTask, FlowTaskHistory.class);
        flowTaskHistory.setCompleteTime(new Date());
        getEngine().getFlowTaskHistoryService().save(flowTaskHistory);
        savePath(context.addPath(gateway.getId()));
    }

    protected List<FlowTask> enterStartGateway(Gateway gateway, PassTaskContext context) {
        //进入网关的时候, 只是创建网关任务, 并且添加路径
        FlowTask gatewayTask = FlowUtils.createStartGatewayTask(gateway, context.getFlowProcessInstance());
        getEngine().getFlowTaskService().save(gatewayTask);
        savePath(context.addPath(gateway.getId()));
        return CommonUtils.asList(gatewayTask);
    }

    protected void passEndGateWay(FlowNode flowNode, FlowTask flowTask, PassTaskContext context) {
        FlowTaskHistory flowTaskHistory = CommonUtils.copyTo(flowTask, FlowTaskHistory.class);
        flowTaskHistory.setCompleteTime(new Date());
        getEngine().getFlowTaskService().removeById(flowTask.getId());
        getEngine().getFlowTaskHistoryService().save(flowTaskHistory);
        getEngine().getFlowGatewayExecutionService().lambdaUpdate()
                .eq(FlowGatewayExecution::getProcessInstanceId, context.getFlowProcessInstance().getId())
                .eq(FlowGatewayExecution::getEndGatewayDefinitionId, flowNode.getId())
                .remove();
        savePath(context.addPath(flowTask.getTaskDefinitionId()));
    }

    protected List<FlowTask> enterEndGateway(Gateway endGateway, PassTaskContext context) {
        List<FlowTask> flowTasks = getEngine().getFlowTaskService().lambdaQuery().eq(FlowTask::getProcessInstanceId, context.getFlowProcessInstance().getId())
                .eq(FlowTask::getTaskDefinitionId, endGateway.getId())
                .list();
        if (flowTasks.isEmpty()) {
            FlowTask endGatewayTask = FlowUtils.createEndGatewayTask(endGateway, context.getFlowProcessInstance());
            endGatewayTask.setExecuteCount(1);

            List<FlowGatewayExecution> executions = getEngine().getFlowGatewayExecutionService().lambdaQuery()
                    .eq(FlowGatewayExecution::getProcessInstanceId, context.getFlowProcessInstance().getId())
                    .eq(FlowGatewayExecution::getEndGatewayDefinitionId, endGateway.getId())
                    .list();
            if (!executions.isEmpty()) {
                FlowGatewayExecution flowGatewayExecution = executions.get(0);
                endGatewayTask.setExecuteThreshold(flowGatewayExecution.getExecuteThreshold());
            } else {
                //流程到了网关结束的节点, 但是没有找到网关开始节点创建出来的execution,
                // 这个问题会出现在指定回退节点的情况下, 如果是这种情况, 那就直接忽略网关结束节点, 让流程继续向后执行
            }
            getEngine().getFlowTaskService().save(endGatewayTask);
            return CommonUtils.asList(endGatewayTask);
        } else {
            FlowTask flowTask = flowTasks.get(0);
            flowTask.setExecuteCount(flowTask.getExecuteCount() + 1);
            getEngine().getFlowTaskService().updateById(flowTask);
            return CommonUtils.asList(flowTask);
        }
    }

    protected List<FlowTask> enterEmpty(FlowNode flowNode, PassTaskContext context) {
        savePath(context.addPath(flowNode.getId()));
        FlowTask emptyTask = FlowUtils.createEmptyTask(flowNode, context.getFlowProcessInstance());
        getEngine().getFlowTaskService().save(emptyTask);
        return CommonUtils.asList(emptyTask);
    }

    protected void passEmptyTask(FlowNode flowNode, FlowTask emptyFlowTask, PassTaskContext context) {
        getEngine().getFlowTaskService().removeById(emptyFlowTask.getId());
        FlowTaskHistory flowTaskHistory = CommonUtils.copyTo(emptyFlowTask, FlowTaskHistory.class);
        getEngine().getFlowTaskHistoryService().save(flowTaskHistory);
    }
}
